﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using ScreenManagement;
using EventFlowLibrary.GameStructure;

namespace EventFlowLibrary.LevelComponents
{
    public sealed class Journal : DrawableGameComponent
    {
        /// <summary>
        /// Whether the journal is currently displayed
        /// </summary>
        public bool IsShown = false;

        /// <summary>
        /// Show debug readings.
        /// </summary>
        public bool ShowDebug = false;

        /// <summary>
        /// Spritebatch to draw necessary items.
        /// </summary>
        private SpriteBatch spriteBatch;

        /// <summary>
        /// Font for journal entries
        /// </summary>
        private SpriteFont font;

        /// <summary>
        /// Background texture of the journal
        /// </summary>
        private Texture2D journalTexture;

        /// <summary>
        /// How many rows we've drawn in our journal
        /// </summary>
        private int rowCount;

        /// <summary>
        /// The top corners of the journal texture in screen coordinates.
        /// </summary>
        private int topX, topY;

        /// <summary>
        /// Our current fade value, between 0.0f and 1.0f
        /// </summary>
        private float alphaFade;

        /// <summary>
        /// Fade in/out rate of journal
        /// </summary>
        private const float alphaFadeRate = 0.005f;

        /// <summary>
        /// String builder to reduce garbage
        /// </summary>
        private StringBuilder sb;

        /// <summary>
        /// Journal text for substituting. Hard coded to get it done...
        /// </summary>
        private readonly string[] journalText = new string[70] {
        "I should enter the house, to attend the party\n",          // 0
        "Where is Miss Havisham?",                                  // 1
        "I have the key to her room - should I enter?\n",           // 2
        "Miss Havisham is dead! Who has done this?\n",              // 3
        "That's it! They all have their crimes, but none of them\n" +
        "   seem to have murdered Miss Havisham... I need to go to\n" +
        "   the front porch and clear my head...",                            // 4
        "A book is on that table. With my name? What is that?\n",   // 5
        "That book... so, that was all she was going to reveal? \n", // 6
        "\n",                                                       // 7
        "\n",                                                       // 8
        "\n",                                                       // 9
        "I should introduce myself to the Duchess Anna Marie \n",   // 10
        "Would Duchess Anna Marie murder, even in her state?\n",    // 11
        "The Duchess is innocent. Then who?\n",                     // 12
        "\n",                                                       // 13
        "\n",                                                       // 14
        "\n",                                                       // 15
        "\n",                                                       // 16
        "\n",                                                       // 17
        "\n",                                                       // 18
        "\n",                                                       // 19
        "I should introduce myself to the Lincolns, Chris and Pam\n",// 20
        "Money must not be all for Chris and Pam. But murder?\n",   // 21
        "I see that the banker and his wife are innocent...\n     Their odd behaviour came from seeking the locket...\n",     // 22
        "     What is the Lincoln's urgency about the locket?\n",        // 23
        "     I've found the locket - what will the banker's wife say?\n",// 24
        "     Why do the Lincolns keep mentioning the Duchess like that?\n",// 25
        "\n",                                                       // 26
        "\n",                                                       // 27
        "\n",                                                       // 28
        "\n",                                                       // 29
        "I should introduce myself to the Russells, John and Margaret\n",// 30
        "Did John and Margaret violate their medical oaths?\n",     // 31
        "The doctor and nurse are innocent...\n     Perhaps overly ambitious and scheming, but innocent.",                   // 32
        "     The doctor and wife were whispering about a scap of paper...\n",// 33
        "     Who took the matches? What for?\n",                        // 34
        "     I've found the doctor's shame! What do they say of that?\n",// 35
        "\n",                                                       // 36
        "\n",                                                       // 37
        "\n",                                                       // 38
        "\n",                                                       // 39
        "I should introduce myself to Mark Jozef\n",                // 40
        "Would Mark Jozef be a hunter of people tonight?\n",        // 41
        "Mark Jozef has killed no one. Here.\n     His love as a young man would have prevented it.\n",                    // 42
        "      Mark Jozef was looking at a torn painting. Where's the rest?\n",// 43
        "      I've found the rest of Mark Jozef's painting!\n",          // 44
        "      He loved Miss Havisham - could he even kill her?\n",                                                       // 45
        "      Who here would know more about Mark Jozef's past?\n", // 46
        "\n",                                                       // 47
        "\n",                                                       // 48
        "\n",                                                       // 49
        "I should introduce myself to Major Andrews\n",             // 50
        "Does the honor of Major Andrews preclude murder?\n",       // 51
        "Major Andrews did not kill Miss Havisham.\n     He was here to excuse excesses in the past, not commit them",               // 52
        "     The Duchess has revealed Major Andrews' life to me...\n",  // 53
        "     Mark Jozef's story may be of interest to Major Andrews.\n", // 54
        "     What is the Major so worried about?\n",                    // 55
        "     Perhaps the Duchess knows more of the Major? She's a gossip.\n", // 56
        "\n",                                                       // 57
        "\n",                                                       // 58
        "\n",                                                       // 59
        "I should introduce myself to Reynaldo Chalcroft\n",        // 60
        "Did Reynaldo Chalcroft dance into murder?\n",              // 61
        "Reynaldo has confessed broke hearts, but did not kill.\n     And I believe his innocence tonight.\n",              // 62
        "     What could Reynaldo hope to find in the library?\n",       // 63
        "     Reynaldo wanted this letter? Are there more?\n",           // 64
        "     I've found his letters... what can he say about them?\n",  // 65
        "     He's acting strange in the library...\n",             // 66
        "\n",                                                       // 67
        "\n",                                                       // 68
        "\n"};                                                      // 69

        public Journal(Game _game, ScreenManager _screenManager)
            : base(_game)
        {
            this.spriteBatch = _screenManager.SpriteBatch;

            this.alphaFade = 0.0f;

            this.DrawOrder = int.MaxValue;
        }

        public override void Initialize()
        {
            sb = new StringBuilder(256, 256);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // TODO make global content manager?
            ContentManager content = new ContentManager(this.Game.Content.ServiceProvider, "Content");

            font = content.Load<SpriteFont>("Fonts/gamefontSmall");
            journalTexture = content.Load<Texture2D>("Textures/Materials/paper2_rotate");

            // Assuming a 1280x720 screen
            topX = 640 - (journalTexture.Width / 2);
            topY = 360 - (journalTexture.Height / 2);
            topY -= 50;

            base.LoadContent();
        }

        public override void Draw(GameTime gameTime)
        {
            if (IsShown)
            {
                // Change our fade
                alphaFade = Math.Min(1.0f, alphaFade + gameTime.ElapsedGameTime.Milliseconds * alphaFadeRate);
            }
            else if (alphaFade > 0)
            {
                // Change our fade
                alphaFade = Math.Max(0.0f, alphaFade - gameTime.ElapsedGameTime.Milliseconds * alphaFadeRate);
            }

            if (alphaFade > 0.0f)
            {
                // Reset our vertical count
                rowCount = 0;

                spriteBatch.Begin();

                spriteBatch.Draw(journalTexture, new Rectangle(topX, topY, journalTexture.Width, journalTexture.Height + 100), Color.White * alphaFade);

                // Draw the game states
#if TRACE
                if (ShowDebug)
                {
                    foreach (KeyValuePair<string, string> state in GlobalVariables.loadVariables.gameState)
                    {
                        sb.Remove(0, sb.Length);
                        sb.Append(state.Key);
                        sb.Append(" : ");
                        sb.Append(state.Value);

                        spriteBatch.DrawString(font, sb, new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        rowCount++;
                    }
                }
#endif
                switch (GlobalVariables.loadVariables.gameState["GameState"])
                {
                    case "Introduction":
                        spriteBatch.DrawString(font, journalText[0], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "IntroductionTwo":
                        spriteBatch.DrawString(font, journalText[0], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "IntroductionThree":
                        break;
                    case "KeyNotFound":
                    case "DoorOpened":
                        spriteBatch.DrawString(font, journalText[1], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "KeyFound":
                        spriteBatch.DrawString(font, journalText[1], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        rowCount += 2;
                        spriteBatch.DrawString(font, journalText[2], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "FirstFoundDead":
                        spriteBatch.DrawString(font, journalText[3], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "AllInnocent":
                        spriteBatch.DrawString(font, journalText[4], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "BookNoticed":
                        spriteBatch.DrawString(font, journalText[4], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        rowCount += 3;
                        spriteBatch.DrawString(font, journalText[5], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    case "EndGame":
                        spriteBatch.DrawString(font, journalText[4], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        rowCount += 3;
                        spriteBatch.DrawString(font, journalText[6], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                        break;
                    default:
                        break;
                }
                rowCount += 2;

                // Only draw when game not finished
                if (GlobalVariables.loadVariables.gameState["GameState"] != "AllInnocent" &&
                    GlobalVariables.loadVariables.gameState["GameState"] != "BookNoticed" &&
                    GlobalVariables.loadVariables.gameState["GameState"] != "EndGame")
                {
                    switch (GlobalVariables.loadVariables.gameState["AMarie"])
                    {
                        case "Introduction":
                            spriteBatch.DrawString(font, journalText[10], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBody":
                        case "AfterBodyAndTalk":
                        case "AfterBodyBeforeLocket":
                        case "AfterBodyAfterLocket":
                        case "AfterBodyBeforeMajor":
                        case "AfterBodyAfterMajor":
                        case "AfterBodyBeforeMJozefPicture":
                        case "AfterBodyAfterMJozefPicture":
                        case "EndGame":
                            spriteBatch.DrawString(font, journalText[11], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "EndGameTwo":
                            spriteBatch.DrawString(font, journalText[12], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        default:
                            break;
                    }
                    rowCount += 2;

                    switch (GlobalVariables.loadVariables.gameState["LincolnGuilt"])
                    {
                        case "Introduction":
                            spriteBatch.DrawString(font, journalText[20], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Suspected":
                        case "AfterBodyAndTalk":
                        case "CanOverhear":
                            spriteBatch.DrawString(font, journalText[21], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterOverheard":
                            spriteBatch.DrawString(font, journalText[21], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[23], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterLocket":
                            spriteBatch.DrawString(font, journalText[21], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[24], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterLocketSuggestDuchess":
                            spriteBatch.DrawString(font, journalText[21], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[25], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Innocent":
                            spriteBatch.DrawString(font, journalText[22], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            break;
                        default:
                            break;
                    }
                    rowCount += 2;

                    switch (GlobalVariables.loadVariables.gameState["RussellGuilt"])
                    {
                        case "Introduction":
                            spriteBatch.DrawString(font, journalText[30], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Suspected":
                        case "AfterBodyAndTalk":
                        case "CanOverhear":
                            spriteBatch.DrawString(font, journalText[31], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterOverheard":
                            spriteBatch.DrawString(font, journalText[31], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[33], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterMatches":
                            spriteBatch.DrawString(font, journalText[31], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[33], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[34], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterFoundScrap":
                            spriteBatch.DrawString(font, journalText[31], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[35], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Innocent":
                            spriteBatch.DrawString(font, journalText[32], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            break;
                        default:
                            break;
                    }
                    rowCount += 2;

                    switch (GlobalVariables.loadVariables.gameState["MJozef"])
                    {
                        case "Introduction":
                            spriteBatch.DrawString(font, journalText[40], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBody":
                        case "AfterBodyAndTalk":
                        case "LookingAtPainting":
                            spriteBatch.DrawString(font, journalText[41], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterLookingAtPainting":
                            spriteBatch.DrawString(font, journalText[41], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[43], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterFoundTornPictureBeforeDuchess":
                        case "AfterFoundTornPictureBeforeDuchessTwo":
                            spriteBatch.DrawString(font, journalText[41], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[44], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterFoundTornPictureAfterDuchess":
                        case "AfterFoundTornPictureAfterDuchessTwo":
                            spriteBatch.DrawString(font, journalText[41], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[45], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "EndGame":
                            spriteBatch.DrawString(font, journalText[42], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            break;
                        default:
                            break;
                    }
                    rowCount += 2;

                    //switch (GlobalVariables.loadVariables.gameState["MajorAndrewsCanTalkAboutHunter"])
                    //{
                    //    case "Can":
                    //        rowCount--;
                    //        spriteBatch.DrawString(font, journalText[54], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                    //        rowCount += 2;
                    //        break;
                    //}
                    switch (GlobalVariables.loadVariables.gameState["AMarieCanDiscussPicture"])
                    {
                        case "Can":
                            rowCount--;
                            spriteBatch.DrawString(font, journalText[46], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount += 2;
                            break;
                    }

                    switch (GlobalVariables.loadVariables.gameState["MajorAndrews"])
                    {
                        case "Introduction":
                            spriteBatch.DrawString(font, journalText[50], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBody":
                        case "AfterBodyTwo":
                            spriteBatch.DrawString(font, journalText[51], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBodyTwoBeforeThree":
                        case "AfterBodyThree":
                            spriteBatch.DrawString(font, journalText[51], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[55], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Suspected":
                            spriteBatch.DrawString(font, journalText[51], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBodyFourBeforeDuchess":
                            spriteBatch.DrawString(font, journalText[51], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[56], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBodyFourAfterDuchess":
                            spriteBatch.DrawString(font, journalText[51], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[53], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "EndGame":
                            spriteBatch.DrawString(font, journalText[52], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            break;
                        default:
                            break;
                    }
                    rowCount += 2;


                    switch (GlobalVariables.loadVariables.gameState["RChalcroft"])
                    {
                        case "Introduction":
                            spriteBatch.DrawString(font, journalText[60], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBody":
                            spriteBatch.DrawString(font, journalText[61], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "AfterBodyAndTalk":
                            spriteBatch.DrawString(font, journalText[61], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[66], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "OverheardInLibrary":
                        case "OverheardInLibraryTwo":
                            spriteBatch.DrawString(font, journalText[61], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[63], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Letter1Found":
                        case "Letter2Found":
                            spriteBatch.DrawString(font, journalText[61], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[64], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "Letter3Found":
                            spriteBatch.DrawString(font, journalText[61], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            spriteBatch.DrawString(font, journalText[65], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            break;
                        case "EndGame":
                            spriteBatch.DrawString(font, journalText[62], new Vector2(topX + 10, topY + 10 + (rowCount * font.LineSpacing)), Color.Black * alphaFade);
                            rowCount++;
                            break;
                        default:
                            break;
                    }
                    rowCount += 2;
                }

                spriteBatch.End();

                base.Draw(gameTime);
            }
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }
    }
}
